﻿'use strict';
var JAYDEN = (function ($, console, undefined) {

	if (typeof String.prototype.startsWith != 'function') {
		String.prototype.startsWith = function (str){
			return this.slice(0, str.length) == str;
		};
	}

	if (typeof String.prototype.endsWith != 'function') {
		String.prototype.endsWith = function (str){
			return this.slice(-str.length) == str;
		};
	}

	if (typeof String.prototype.replaceAll != 'function') {
		String.prototype.replaceAll = function (replace, replacement){
			return this.replace(new RegExp(replace, 'g'),replacement);
		};
	}

	// main object
	var jayden = {};

	jayden.undefined = undefined;
	jayden.$ = $;
	jayden.console = console;

	console.log = console.log || function () { /* do nothing */ };
	console.warn = console.warn || console.log;
	console.error = console.error || console.log;
	console.info = console.info || console.log;

	jayden.isStrict = (function() { return !this; })();
	if(!jayden.isStrict) {
		jayden.console.info('this browser does not implement strict mode.');
	}

	// http://diveintohtml5.info/detect.html
	var html5 = jayden.html5 = {};
	html5.canvas = (!!document.createElement('canvas').getContext);
	html5.details = ($('<details open="open"><summary>s</summary></details>')[0].open !== undefined);
	html5.input = (function() {
		var input = document.createElement('input');
		return {
			placeholder: ('placeholder' in input),
			autofocus: ('autofocus' in input),
			required: ('required' in input),
			pattern: ('pattern' in input),
			list: ('list' in input),
			type: (function(){
				var checkSupportHtml5InputType = function (typeName) {
					input.setAttribute('type', typeName)
					return input.type !== 'text';
				};
			
				return {
					search: checkSupportHtml5InputType('search'),
					number: checkSupportHtml5InputType('number'),
					range: checkSupportHtml5InputType('range'),
					color: checkSupportHtml5InputType('color'),
					tel: checkSupportHtml5InputType('tel'),
					url: checkSupportHtml5InputType('url'),
					email: checkSupportHtml5InputType('email'),
					date: checkSupportHtml5InputType('date'),
					month: checkSupportHtml5InputType('month'),
					week: checkSupportHtml5InputType('week'),
					time: checkSupportHtml5InputType('time'),
					datetime: checkSupportHtml5InputType('datetime'),
					'datetime-local': checkSupportHtml5InputType('datetime-local'),
					file: {
						multiple: ($('<input type="file" multiple="multiple" />')[0].files !== undefined)
					}
				};

			} ())
		};
	}());


	jayden.ajax = {};

	// array of objects that must have a handle function
	jayden.ajax.handlers = [];

	jayden.sfn = {};

	jayden.sfn.successAjax = function (data, textStatus, jqXHR) {
		var handlers = jayden.ajax.handlers;
		var handler, handlerIdx;
		for(handlerIdx = 0;handlerIdx < handlers.length; handlerIdx ++) {
			handler = handlers[handlerIdx];
			if(handler.handle)
				handler.handle(data, textStatus, jqXHR);
		}
	};

	jayden.sfn.errorAjax = function (jqXHR, textStatus, errorThrown) {
		console.error('jayden.sfn.errorAjax: ajax request failed. (' + textStatus + ')');
	};
	jayden.sfn.checkFormValidity = function($form) {
		if(!(html5.input.required && html5.input.pattern)) {
			var validity = $form.checkInputsValidity();
			if(validity.error === -1)
				alert('Field is required.');
			else if(validity.error === -2)
				alert('Field does not match the pattern.');
			if(validity.first)
				validity.first.focus();
			return validity.error === 1;
		}
		return true;
	};
	jayden.sfn.submitAjax = function (form, success, error) {
		var $form = $(form);
		if(!jayden.sfn.checkFormValidity($form))
			return false;
		var values = $form.serializeArray();
		values.push({name:'format',value:'json'});
		jayden.sfn.submitAjaxData(values, $form.attr('action'), $form.attr('method'), success, error);
	};

	jayden.sfn.submitAjaxData = function(values, url, type, success, error) {
		if(!success)
			success = jayden.sfn.successAjax;
		if(!error)
			error = jayden.sfn.errorAjax;
		if(!type)
			type = 'post';
		$.ajax({
			url: url,
			type: type,
			data: values,
			success: success,
			error: error
		});
		return false;
	};

	jayden.sfn.submitAjaxFormData = function(values, url, type, progress, success, error, canceled) {
		try {
			//init variables (should fail if not supported)
			var xhr = new XMLHttpRequest();
			var fd = new FormData();
			var idx = 0;

			// add object to the form data
			for(;idx<values.length;idx++)
				fd.append(values[idx].name, values[idx].value);
	
			// bind event listener
			if(progress)
				xhr.upload.addEventListener("progress", progress, false);
			if(success)
				xhr.addEventListener("load", success, false);
			if(error)
				xhr.addEventListener("error", error, false);
			if(canceled)
				xhr.addEventListener("abort", canceled, false);

			// open an http stream and send the datas
			xhr.open(type || 'post', url || window.location.href);
			xhr.send(fd);

			return false;
		} catch(err) {
			return true;
		}
	};


	

	jayden.sfn.toUserFriendlyByteLength = function(value) {
		if(value < 1024)
			return value + ' bytes';
		if(value < 1024 * 1024)
			return parseInt(value / 1024) + ' Kbytes';
		if(value < 1024 * 1024 * 1024)
			return parseInt(value / (1024 * 1024)) + ' Mbytes';
		return parseInt(value / (1024 * 1024 * 1024)) + ' Gbytes';
	};


	// add a custamizable overlay over an element (if none is present)
	jayden.sfn.startLoading = function (elt, parameters) {
		var $elt = $(elt);
		if(!$elt.data('isLoading')) {
			if(!parameters)
				parameters = {
					singleLine: true,
					overlayImg: '/Images/ajaxLoading-circle.gif',
					overlayText: ''
				};
			if(!parameters.overlayHtml) {
				parameters.overlayHtml = '<div class="overlay"><img src="' + parameters.overlayImg + '" alt="Loading" />' + parameters.overlayText + '</div>';
			}
			var $overlay = $(parameters.overlayHtml).css('position', 'absolute');
			$elt.data('isLoading', $overlay);
			var eltOffset = $elt.offset();
			$('body').append($overlay);
			$overlay.show().offset({ left: eltOffset.left, top: eltOffset.top }).width($elt.width()).height($elt.height());
			if(parameters.singleLine)
				$overlay.css('line-height', $overlay.height() + 'px');
		}
	};

	// remove an existing overlay from an element
	jayden.sfn.stopLoading = function (elt) {
		var $elt = $(elt);
		var $overlay = $elt.data('isLoading');
		if($overlay) {
			$overlay.remove();
			$elt.removeData('isLoading');
		}
	}


	// check the validity of the input for html5 attributes
	$.fn.checkInputValidity = function() {
		var required = (this.attr('required') === 'required');
		var pattern = this.attr('pattern');
		var value = this.val();
		if(required &&
			(!value || 
				value.length === 0 || 
				(!html5.input.placeholder && this.hasClass('placeholder'))
			)
		)
			return -1;
		if(pattern) {
			var regex = new RegExp(pattern);
			if(!regex.test(value))
				return -2;
		}
		return 1;
	};

	// check the validity of all children in inputs and return an object containig the first error
	$.fn.checkInputsValidity = function() {
		var $firstWrong = null;
		var errorCode = 1;
		$(':input', this).each(function(i, e) {
			if(!$firstWrong) {
				var $e = $(e);
				var code = $e.checkInputValidity();
				if(code < 0) {
					$firstWrong = $e;
					errorCode = code;
				}
			}
		});
		return {
			first: $firstWrong,
			error: errorCode
		};
	};

	if(!html5.input.placeholder) {
		console.info('this browser does not implements HTML5 <input> "placeholder" attribute.');
		$(function() {
			$('input[placeholder]').blur(function() {
				var $this = $(this);
				if($this.val() === '' && $this.attr('type') !== 'password') {
					$this.val($this.attr('placeholder')).addClass('placeholder');
				}
			}).focus(function() {
				var $this = $(this);
				if($this.hasClass('placeholder')) {
					$this.val('').removeClass('placeholder');
				}
			}).blur();
		});
	}
	if(!html5.input.autofocus) {
		console.info('this browser does not implements HTML5 <input> "autofocus" attribute.');
		$(function() {
			$('input[autofocus]').focus();
		});
	}
	if(!html5.input.list) {
		console.info('this browser does not implements HTML5 <input> "list" attribute (not implemented).');
		// not implemented
	}
	if(!html5.input.type.file.multiple) {
		console.info('this browser does not implements HTML5 <input type="file"> "multiple" attribute (not implemented).');
		// not implemented
	}
	if(!html5.details) {
		console.info('this browser does not implements HTML5 <details> and <summary> tags.');
		$(function() {
			$('details > summary').each(function() {
				var $this = $(this);
				var $details = $this.parent();
				var state = $details.attr('open');
				var selector = ':not(summary)';
				var toggle = function() {
					state = $details.attr('open');
					if(!state) {
						state = 'open';
						$details.children(selector).show();
						$details.attr('open', 'open');
					} else {
						$details.removeAttr('open');
						$details.children(selector).hide();
					}
				};
				if(!state)
					$details.children(selector).hide();
				$this.click(toggle);
			});
		});
	}

	if(!(html5.input.required && html5.input.pattern)) {
		console.info('this browser does not implements HTML5 <input> "required" or "pattern" attribute.');
		$('body').on('submit', 'form', function(e) {
			if(!jayden.sfn.checkFormValidity($(this))) {
				e.preventDefault();
				e.stopPropagation();
				return false;
			}
			return true;
		});
	}

	console.info('JAYDEN loaded successfully.');

	return jayden;
}(jQuery, typeof(console) === 'undefined' ? {} : console));


